`timescale 1ns/1ps
`default_nettype none

/* NOTE
* 本模块负责：
* - 初始化SDRAM
* - 周期性执行Auto Refresh命令
* - 根据优先级将SDRAM控制权交给各模块
* - 优先级mux0->mux1->mux2 ->mux3->mux4 
*/

module sdram_mux
#(parameter
    DQ_BITS = 32, // width of data
    BA_BITS = 2,  // width of bank address
    RA_BITS = 11, // width of row address
    CA_BITS = 8   // width of column address
) (
    // system signal
    input  wire                 I_sclk,
    input  wire                 I_rst_n,
    // status
    output wire                 O_sdram_ready,
    // mux 0
    input  wire                 I_mux0_req,
    output wire                 O_mux0_ack,
    output wire                 O_mux0_irq,
    input  wire                 I_mux0_cs_n,
    input  wire                 I_mux0_ras_n,
    input  wire                 I_mux0_cas_n,
    input  wire                 I_mux0_we_n,
    input  wire [BA_BITS-1:0]   I_mux0_ba,
    input  wire [RA_BITS-1:0]   I_mux0_addr,
    input  wire [DQ_BITS-1:0]   I_mux0_dq_out,
    output wire [DQ_BITS-1:0]   O_mux0_dq_in,
    input  wire                 I_mux0_dq_oe,
    input  wire [DQ_BITS/8-1:0] I_mux0_dqm,
    // mux 1
    input  wire                 I_mux1_req,
    output wire                 O_mux1_ack,
    output wire                 O_mux1_irq,
    input  wire                 I_mux1_cs_n,
    input  wire                 I_mux1_ras_n,
    input  wire                 I_mux1_cas_n,
    input  wire                 I_mux1_we_n,
    input  wire [BA_BITS-1:0]   I_mux1_ba,
    input  wire [RA_BITS-1:0]   I_mux1_addr,
    input  wire [DQ_BITS-1:0]   I_mux1_dq_out,
    output wire [DQ_BITS-1:0]   O_mux1_dq_in,
    input  wire                 I_mux1_dq_oe,
    input  wire [DQ_BITS/8-1:0] I_mux1_dqm,
    // mux 2
    input  wire                 I_mux2_req,
    output wire                 O_mux2_ack,
    output wire                 O_mux2_irq,
    input  wire                 I_mux2_cs_n,
    input  wire                 I_mux2_ras_n,
    input  wire                 I_mux2_cas_n,
    input  wire                 I_mux2_we_n,
    input  wire [BA_BITS-1:0]   I_mux2_ba,
    input  wire [RA_BITS-1:0]   I_mux2_addr,
    input  wire [DQ_BITS-1:0]   I_mux2_dq_out,
    output wire [DQ_BITS-1:0]   O_mux2_dq_in,
    input  wire                 I_mux2_dq_oe,
    input  wire [DQ_BITS/8-1:0] I_mux2_dqm,
    // mux 3
    input  wire                 I_mux3_req,
    output wire                 O_mux3_ack,
    output wire                 O_mux3_irq,
    input  wire                 I_mux3_cs_n,
    input  wire                 I_mux3_ras_n,
    input  wire                 I_mux3_cas_n,
    input  wire                 I_mux3_we_n,
    input  wire [BA_BITS-1:0]   I_mux3_ba,
    input  wire [RA_BITS-1:0]   I_mux3_addr,
    input  wire [DQ_BITS-1:0]   I_mux3_dq_out,
    output wire [DQ_BITS-1:0]   O_mux3_dq_in,
    input  wire                 I_mux3_dq_oe,
    input  wire [DQ_BITS/8-1:0] I_mux3_dqm,
    // mux 4
    input  wire                 I_mux4_req,
    output wire                 O_mux4_ack,
    output wire                 O_mux4_irq,
    input  wire                 I_mux4_cs_n,
    input  wire                 I_mux4_ras_n,
    input  wire                 I_mux4_cas_n,
    input  wire                 I_mux4_we_n,
    input  wire [BA_BITS-1:0]   I_mux4_ba,
    input  wire [RA_BITS-1:0]   I_mux4_addr,
    input  wire [DQ_BITS-1:0]   I_mux4_dq_out,
    output wire [DQ_BITS-1:0]   O_mux4_dq_in,
    input  wire                 I_mux4_dq_oe,
    input  wire [DQ_BITS/8-1:0] I_mux4_dqm,

    // sdram signals
    output wire                 O_sdram_cke,    // CKE
    output wire                 O_sdram_cs_n,   // CS#
    output wire                 O_sdram_ras_n,  // RAS#
    output wire                 O_sdram_cas_n,  // CAS#
    output wire                 O_sdram_we_n,   // WE#
    output wire [BA_BITS-1:0]   O_sdram_ba,     // BA
    output wire [RA_BITS-1:0]   O_sdram_addr,   // A
    output wire [DQ_BITS/8-1:0] O_sdram_dqm,    // DQM
    inout  tri  [DQ_BITS-1:0]   IO_sdram_dq     // DQ output
);
//------------------------Parameter----------------------
`include "sdram_common.vh"

// fsm
localparam
    INIT  = 4'd0,
    PALL0 = 4'd1,
    PALL1 = 4'd2,
    IREF0 = 4'd3,
    IREF1 = 4'd4,
    MRS0  = 4'd5,
    MRS1  = 4'd6,
    MUX   = 4'd7,
    AREF0 = 4'd8,
    AREF1 = 4'd9;

//------------------------Local signal-------------------
// fsm
reg  [3:0]  state;
reg  [3:0]  next;

// counter
reg  [15:0] delay_counter;
reg  [3:0]  loop_counter;

// bus mux
wire [4:0]  mux_req;
reg  [4:0]  mux_sel;
reg  [4:0]  sel_buf;

// sdram
reg  [3:0]           cmd_buf;  // cmd buffer
reg  [BA_BITS-1:0]   ba_buf;   // ba buffer
reg  [RA_BITS-1:0]   addr_buf; // addr buffer
reg  [DQ_BITS-1:0]   dq_buf;   // dq buffer
reg                  dq_oe;    // dq output enable
reg  [DQ_BITS/8-1:0] dqm_buf;  // dqm buffer
reg  [DQ_BITS-1:0]   dq_in;    // dq input buffer

reg  [3:0]           cmd_buf0;
reg  [BA_BITS-1:0]   ba_buf0;
reg  [RA_BITS-1:0]   addr_buf0;
reg  [DQ_BITS-1:0]   dq_buf0;
reg                  dq_oe0;
reg  [DQ_BITS/8-1:0] dqm_buf0;

// auto refresh
reg [15:0]  refresh_timer;
reg         need_refresh;

// status
reg         sdram_ready;

//------------------------Instantiation------------------

//------------------------Body---------------------------
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
// state
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= INIT;
    else
        state <= next;
end

// next
always @(*) begin
    case (state)
        INIT: begin
            if (delay_counter >= DELAY_PU)
                next = PALL0;
            else
                next = INIT;
        end

        PALL0: begin
            next = PALL1;
        end

        PALL1: begin
           if (delay_counter >= DELAY_RP)
               next = IREF0;
           else
               next = PALL1;
        end

        IREF0: begin
            next = IREF1;
        end

        IREF1: begin
            if (delay_counter < DELAY_RFC)
                next = IREF1;
            else if (loop_counter >= LOOP_IREF)
                next = MRS0;
            else
                next = IREF0;
        end

        MRS0: begin
            next = MRS1;
        end

        MRS1: begin
           if (delay_counter >= DELAY_MRD)
               next = MUX;
           else
               next = MRS1;
        end

        MUX: begin
            if (|mux_req)
                next = MUX;
            else if (need_refresh)
                next = AREF0;
            else
                next = MUX;
        end

        AREF0: begin
            next = AREF1;
        end

        AREF1: begin
            if (delay_counter < DELAY_RFC)
                next = AREF1;
            else if (loop_counter >= LOOP_AREF)
                next = MUX;
            else
                next = AREF0;
        end

        default: begin
            next = MUX;
        end
    endcase
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++counter++++++++++++++++++++++++
// delay_counter
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        delay_counter <= 1'b0;
    else if (state == PALL0 || state == IREF0 || state == MRS0 || state == AREF0)
        delay_counter <= 2'd2;
    else
        delay_counter <= delay_counter + 1'b1;
end

// loop_counter
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        loop_counter <= 1'b0;
    else if (state == INIT || state == MUX)
        loop_counter <= 1'b0;
    else if (state == IREF0 || state == AREF0)
        loop_counter <= loop_counter + 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++bus mux++++++++++++++++++++++++
/* NOTE
* - 外部模块请求操作SDRAM时需将_req信号置1
* - 当_ack信号为1时，相应的模块实际拥有SDRAM控制权
* - 外部模块_req信号必须一直保持1，直到它想放弃SDRAM控制权
* - 只有在MUX状态下，外部模块才能获取SDRAM控制权
* - 模块控制权切换0开销
*/

assign O_mux0_ack = mux_sel[0];
assign O_mux1_ack = mux_sel[1];
assign O_mux2_ack = mux_sel[2];
assign O_mux3_ack = mux_sel[3];
assign O_mux4_ack = mux_sel[4];

assign O_mux0_irq = 1'b0;
assign O_mux1_irq = I_mux0_req;
assign O_mux2_irq = I_mux0_req | I_mux1_req;
assign O_mux3_irq = I_mux0_req | I_mux1_req | I_mux2_req;
assign O_mux4_irq = I_mux0_req | I_mux1_req | I_mux2_req | I_mux3_req;

assign O_mux0_dq_in = dq_in;
assign O_mux1_dq_in = dq_in;
assign O_mux2_dq_in = dq_in;
assign O_mux3_dq_in = dq_in;
assign O_mux4_dq_in = dq_in;

assign mux_req = {I_mux4_req,I_mux3_req, I_mux2_req, I_mux1_req, I_mux0_req};

// mux_sel
always @(*) begin
    if (state != MUX) // 非MUX状态SDRAM由内部控制
        mux_sel = 5'b00000;
    else if ((sel_buf & mux_req) != 1'b0) // 上个周期已选中，且本周期_req未撤销，控制权不变
        mux_sel = sel_buf;
    // else if (mux_req[0]) // 按优先级分配
        // mux_sel = 5'b00001;
    // else if (mux_req[1])
        // mux_sel = 5'b00010;
    // else if (mux_req[2])
        // mux_sel = 5'b00100;
    // else if (mux_req[3])
        // mux_sel = 5'b01000;
    // else if (mux_req[4])
        // mux_sel = 5'b10000;
        
    else case(mux_req[4:0])
        5'b00001,
        5'b00011,
        5'b00101,
        5'b00111,
        
        5'b01001,
        5'b01011,
        5'b01101,
        5'b01111,
        
        5'b10001,
        5'b10011,
        5'b10101,
        5'b10111,
        
        5'b11001,
        5'b11011,
        5'b11101,
        5'b11111:
            mux_sel = 5'b00001;
        5'b00010,
        5'b00110,
        5'b01010,
        5'b01110,
        
        5'b10010,
        5'b10110,
        5'b11010,
        5'b11110:
            mux_sel = 5'b00010;
        5'b00100,
        5'b01100,
        5'b10100,
        5'b11100:
            mux_sel = 5'b00100;
        5'b01000,
        5'b11000:
            mux_sel = 5'b01000;
        5'b10000:
            mux_sel = 5'b10000;
        5'b00000:
             mux_sel = 5'b00000;
        endcase
       
end

// sel_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        sel_buf <= 1'b0;
    else
        sel_buf <= mux_sel;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++sdram signals++++++++++++++++++
assign O_sdram_cke   = 1'b1;
assign O_sdram_cs_n  = cmd_buf0[3];
assign O_sdram_ras_n = cmd_buf0[2];
assign O_sdram_cas_n = cmd_buf0[1];
assign O_sdram_we_n  = cmd_buf0[0];
assign O_sdram_ba    = ba_buf0;
assign O_sdram_addr  = addr_buf0;
assign O_sdram_dqm   = dqm_buf0;
assign IO_sdram_dq   = dq_oe0? dq_buf0 : {DQ_BITS{1'bz}};

always @(posedge I_sclk) begin
    cmd_buf0  <= cmd_buf;
    ba_buf0   <= ba_buf;
    addr_buf0 <= addr_buf;
    dq_buf0   <= dq_buf;
    dq_oe0    <= dq_oe;
    dqm_buf0  <= dqm_buf;
end

// cmd_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cmd_buf <= SD_CMD_NOP;
    else if (state == INIT)
        cmd_buf <= SD_CMD_NOP;
    else if (state == PALL0)
        cmd_buf <= SD_CMD_PRE;
    else if (state == IREF0 || state == AREF0)
        cmd_buf <= SD_CMD_REF;
    else if (state == MRS0)
        cmd_buf <= SD_CMD_MRS;
    else if (state == MUX) begin
        if (mux_sel[0])
            cmd_buf <= {I_mux0_cs_n, I_mux0_ras_n, I_mux0_cas_n, I_mux0_we_n};
        else if (mux_sel[1])
            cmd_buf <= {I_mux1_cs_n, I_mux1_ras_n, I_mux1_cas_n, I_mux1_we_n};
        else if (mux_sel[2])
            cmd_buf <= {I_mux2_cs_n, I_mux2_ras_n, I_mux2_cas_n, I_mux2_we_n};
        else if (mux_sel[3])
            cmd_buf <= {I_mux3_cs_n, I_mux3_ras_n, I_mux3_cas_n, I_mux3_we_n};
        else if (mux_sel[4])
            cmd_buf <= {I_mux4_cs_n, I_mux4_ras_n, I_mux4_cas_n, I_mux4_we_n};
        else
            cmd_buf <= SD_CMD_NOP;
            
        // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // cmd_buf <= {I_mux0_cs_n, I_mux0_ras_n, I_mux0_cas_n, I_mux0_we_n};
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // cmd_buf <= {I_mux1_cs_n, I_mux1_ras_n, I_mux1_cas_n, I_mux1_we_n};
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // cmd_buf <= {I_mux2_cs_n, I_mux2_ras_n, I_mux2_cas_n, I_mux2_we_n};
            // 5'b01000,
            // 5'b11000:
                // cmd_buf <= {I_mux3_cs_n, I_mux3_ras_n, I_mux3_cas_n, I_mux3_we_n};
            // 5'b10000:
                // cmd_buf <= {I_mux4_cs_n, I_mux4_ras_n, I_mux4_cas_n, I_mux4_we_n};
            // 5'b00000:
                // cmd_buf <= SD_CMD_NOP;
        // endcase
    end
    else
        cmd_buf <= SD_CMD_NOP;
end

// ba_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        ba_buf <= 1'b0;
    else if (state == MRS0)
        ba_buf <= 1'b0;
    else if (state == MUX) begin
        if (mux_sel[0])
            ba_buf <= I_mux0_ba;
        else if (mux_sel[1])
            ba_buf <= I_mux1_ba;
        else if (mux_sel[2])
            ba_buf <= I_mux2_ba;
        else if (mux_sel[3])
            ba_buf <= I_mux3_ba;
        else if (mux_sel[4])
            ba_buf <= I_mux4_ba;
            
         // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // ba_buf <= I_mux0_ba;
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // ba_buf <= I_mux1_ba;
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // ba_buf <= I_mux2_ba;
            // 5'b01000,
            // 5'b11000:
                // ba_buf <= I_mux3_ba;
            // 5'b10000:
                // ba_buf <= I_mux4_ba;
            // 5'b00000:
                // ba_buf <= I_mux0_ba;
        // endcase
            
    end
end

// addr_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        addr_buf <= 1'b0;
    else if (state == PALL0)
        addr_buf[10] <= 1'b1;
    else if (state == MRS0)
        addr_buf <= {SD_MR_CL, SD_MR_WT, SD_MR_BL};
    else if (state == MUX) begin
        if (mux_sel[0])
            addr_buf <= I_mux0_addr;
        else if (mux_sel[1])
            addr_buf <= I_mux1_addr;
        else if (mux_sel[2])
            addr_buf <= I_mux2_addr;
        else if (mux_sel[3])
            addr_buf <= I_mux3_addr;
        else if (mux_sel[4])
            addr_buf <= I_mux4_addr;
            
         // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // addr_buf <= I_mux0_addr;
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // addr_buf <= I_mux1_addr;
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // addr_buf <= I_mux2_addr;
            // 5'b01000,
            // 5'b11000:
                // addr_buf <= I_mux3_addr;
            // 5'b10000:
                // addr_buf <= I_mux4_addr;
            // 5'b00000:
                // addr_buf <= addr_buf;
        // endcase
            
    end
end

// dq_buf
always @(posedge I_sclk) begin
    if (state == MUX) begin
        if (mux_sel[0])
            dq_buf <= I_mux0_dq_out;
        else if (mux_sel[1])
            dq_buf <= I_mux1_dq_out;
        else if (mux_sel[2])
            dq_buf <= I_mux2_dq_out;
        else if (mux_sel[3])
            dq_buf <= I_mux3_dq_out;
        else if (mux_sel[4])
            dq_buf <= I_mux4_dq_out;
        else
            dq_buf <= 1'b0;
            
        // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // dq_buf <= I_mux0_dq_out;
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // dq_buf <= I_mux1_dq_out;
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // dq_buf <= I_mux2_dq_out;
            // 5'b01000,
            // 5'b11000:
                // dq_buf <= I_mux3_dq_out;
            // 5'b10000:
                // dq_buf <= I_mux4_dq_out;
            // 5'b00000:
                // dq_buf <= 1'b0;
        // endcase
    end
    else
        dq_buf <= 1'b0;
end

// dq_oe
always @(posedge I_sclk) begin
    if (state == MUX) begin
        if (mux_sel[0])
            dq_oe <= I_mux0_dq_oe;
        else if (mux_sel[1])
            dq_oe <= I_mux1_dq_oe;
        else if (mux_sel[2])
            dq_oe <= I_mux2_dq_oe;
        else if (mux_sel[3])
            dq_oe <= I_mux3_dq_oe;
        else if (mux_sel[4])
            dq_oe <= I_mux4_dq_oe;
        else
            dq_oe <= 1'b0;
       // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // dq_oe <= I_mux0_dq_oe;
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // dq_oe <= I_mux1_dq_oe;
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // dq_oe <= I_mux2_dq_oe;
            // 5'b01000,
            // 5'b11000:
                // dq_oe <= I_mux3_dq_oe;
            // 5'b10000:
                // dq_oe <= I_mux4_dq_oe;
            // 5'b00000:
                // dq_oe <= 1'b0;
        // endcase
    end
    else
        dq_oe <= 1'b0;
end

// dqm_buf
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        dqm_buf <= 1'b0;
    else if (state == MUX) begin
        if (mux_sel[0])
            dqm_buf <= I_mux0_dqm;
        else if (mux_sel[1])
            dqm_buf <= I_mux1_dqm;
        else if (mux_sel[2])
            dqm_buf <= I_mux2_dqm;
        else if (mux_sel[3])
            dqm_buf <= I_mux3_dqm;
        else if (mux_sel[4])
            dqm_buf <= I_mux4_dqm;
        else
            dqm_buf <= 1'b0;
            
        // case(mux_sel[4:0])
            // 5'b00001,
            // 5'b00011,
            // 5'b00101,
            // 5'b00111,
            
            // 5'b01001,
            // 5'b01011,
            // 5'b01101,
            // 5'b01111,
            
            // 5'b10001,
            // 5'b10011,
            // 5'b10101,
            // 5'b10111,
            
            // 5'b11001,
            // 5'b11011,
            // 5'b11101,
            // 5'b11111:
                // dqm_buf <= I_mux0_dqm;
            // 5'b00010,
            // 5'b00110,
            // 5'b01010,
            // 5'b01110,
            
            // 5'b10010,
            // 5'b10110,
            // 5'b11010,
            // 5'b11110:
                // dqm_buf <= I_mux1_dqm;
            // 5'b00100,
            // 5'b01100,
            // 5'b10100,
            // 5'b11100:
                // dqm_buf <= I_mux2_dqm;
            // 5'b01000,
            // 5'b11000:
                // dqm_buf <= I_mux3_dqm;
            // 5'b10000:
                // dqm_buf <= I_mux4_dqm;
            // 5'b00000:
                // dqm_buf <= 1'b0;
        // endcase
    end
    else
        dqm_buf <= 1'b0;
end

// dq_in
always @(posedge I_sclk) begin
    dq_in <= IO_sdram_dq;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++auto refresh+++++++++++++++++++
// refresh_timer
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        refresh_timer <= 1'b1;
    else if (state == PALL0)
        refresh_timer <= 1'b1;
    else if (refresh_timer >= REFRESH_CYCLE)
        refresh_timer <= 1'b1;
    else
        refresh_timer <= refresh_timer + 1'b1;
end

// need_refresh
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        need_refresh <= 1'b0;
    else if (state == PALL0)
        need_refresh <= 1'b0;
    else if (refresh_timer >= REFRESH_CYCLE)
        need_refresh <= 1'b1;
    else if (state == AREF0)
        need_refresh <= 1'b0;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++status+++++++++++++++++++++++++
assign O_sdram_ready = sdram_ready;

// sdram_ready
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        sdram_ready <= 1'b0;
    else if (state == MUX)
        sdram_ready <= 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fdm=marker fenc=utf-8:
